/*
 * (C) Copyright 2014-2016, by Dimitrios Michail
 *
 * JHeaps Library
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jheaps.tree

import org.jheaps.Heap
import org.junit.Assert
import org.junit.BeforeClass
import org.junit.Test
import java.io.*

abstract class AbstractComparatorLongHeapTest : AbstractLongHeapTest() {
    protected abstract fun createHeap(comparator: Comparator<Long?>?): Heap<Long>

    private class TestComparator : Comparator<Long?>, Serializable {
        override fun compare(o1: Long?, o2: Long?): Int {
            return if (o1!! < o2!!) {
                1
            } else if (o1 > o2) {
                -1
            } else {
                0
            }
        }

        companion object {
            private const val serialVersionUID = 1L
        }
    }

    @Test
    fun testWithComparator() {
        val h = createHeap(comparator)

        var i: Long = 0
        while (i < SIZE) {
            h.insert(i)
            Assert.assertEquals(i, h.findMin())
            Assert.assertFalse(h.isEmpty)
            Assert.assertEquals(h.size(), i + 1)
            i++
        }

        i = (SIZE - 1).toLong()
        while (i >= 0) {
            Assert.assertEquals(h.findMin(), i)
            h.deleteMin()
            i--
        }
    }

    @Test
    fun testOnly4Reverse() {
        val h = createHeap(comparator)

        Assert.assertTrue(h.isEmpty)

        h.insert(780L)
        Assert.assertEquals(h.size(), 1)
        Assert.assertEquals(780, h.findMin())

        h.insert(-389L)
        Assert.assertEquals(h.size(), 2)
        Assert.assertEquals(780, h.findMin())

        h.insert(306L)
        Assert.assertEquals(h.size(), 3)
        Assert.assertEquals(780, h.findMin())

        h.insert(579L)
        Assert.assertEquals(h.size(), 4)
        Assert.assertEquals(780, h.findMin())

        h.deleteMin()
        Assert.assertEquals(h.size(), 3)
        Assert.assertEquals(579, h.findMin())

        h.deleteMin()
        Assert.assertEquals(h.size(), 2)
        Assert.assertEquals(306, h.findMin())

        h.deleteMin()
        Assert.assertEquals(h.size(), 1)
        Assert.assertEquals(-389, h.findMin())

        h.deleteMin()
        Assert.assertEquals(h.size(), 0)

        Assert.assertTrue(h.isEmpty)
    }

    @Test
    @Throws(IOException::class, ClassNotFoundException::class)
    fun testSerializableWithComparator() {
        var h = createHeap(comparator)

        for (i in 0..14) {
            h.insert(i.toLong())
        }

        // write
        val baos = ByteArrayOutputStream()
        val oos = ObjectOutputStream(baos)
        oos.writeObject(h)
        oos.close()
        val data = baos.toByteArray()

        // read
        val ois = ObjectInputStream(ByteArrayInputStream(data))
        val o = ois.readObject()
        ois.close()
        h = o as Heap<Long>

        for (i in 0..14) {
            Assert.assertEquals((15 - i).toLong(), h.size())
            Assert.assertEquals((15 - i - 1).toLong(), h.findMin())
            h.deleteMin()
        }
        Assert.assertTrue(h.isEmpty)
    }

    companion object {
        @JvmStatic
        protected var comparator: Comparator<Long?>? = null

        @JvmStatic
        @BeforeClass
        fun setUpClass(): Unit {
            comparator = TestComparator()
        }
    }
}
